package com.genghis.rapidcrm.web.view.mapper;

import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.util.UrlPathHelper;

import javax.servlet.http.HttpServletRequest;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author xulixin
 */
public class RapidRequestModuleMappingHandler {

    private final UrlPathHelper urlPathHelper = new UrlPathHelper();

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    private final String[] bestPatterns = {
            "/{module}",
            "/{module}/",
            "/{module}/{action}",
            "/{module}/{action}/",
            "/{parent}:{module}",
            "/{parent}:{module}/",
            "/{parent}:{module}/{action}",
            "/{parent}:{module}/{action}/"
    };

    public void handleMatch(HttpServletRequest request, Object bean) {
        String lookupPath = urlPathHelper.getLookupPathForRequest(request);
        Map<String, String> map;
        for (String bestPattern : bestPatterns) {
            try {
                map = pathMatcher.extractUriTemplateVariables(bestPattern, lookupPath);
                if (map != null && map.size() > 0) {
                    copyMapValueToBeanProperty(bean, map);
                }
            } catch (Exception e) {
                continue;
            }
        }
    }

    private void copyMapValueToBeanProperty(Object bean, Map<String, String> map)
            throws IntrospectionException, InvocationTargetException, IllegalAccessException {

        PropertyDescriptor[] propertyDescriptors =
                Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
        for (PropertyDescriptor descriptor : propertyDescriptors) {
            if (map.containsKey(descriptor.getName())) {
                Method setter = descriptor.getWriteMethod();
                if (setter != null) {
                    setter.setAccessible(true);
                    setter.invoke(bean, map.get(descriptor.getName()));
                }
            }
        }
    }
}
